package com.ehome.poct.core.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import com.ehome.exception.BizException;
import com.ehome.poct.base.api.dto.device.TestDeviceDTO;
import com.ehome.poct.core.api.common.DomainBizCode;
import com.ehome.poct.core.api.common.StripTypeConst;
import com.ehome.poct.core.api.common.ValueConst;
import com.ehome.poct.core.api.dto.check.*;
import com.ehome.poct.core.api.dto.check.AlgoRequestLog;
import com.ehome.poct.core.api.dto.check.CheckDataDTO;
import com.ehome.poct.core.api.dto.check.SampleMaterialDTO;
import com.ehome.poct.base.api.dto.doctor.ClinicDTO;
import com.ehome.poct.core.api.dto.check.gold.TestConfPoctStripMappingDTO;
import com.ehome.poct.core.api.dto.check.gold.TestConfPoctStripTypeDTO;
import com.ehome.poct.core.api.virtual.CheckService;
import com.ehome.poct.core.api.virtual.GoldAlgoService;
import com.ehome.poct.core.api.vo.check.CellBoardValidVO;
import com.ehome.poct.core.api.vo.check.CheckProcessResultVO;
import com.ehome.poct.core.api.vo.check.CheckStatusVO;
import com.ehome.poct.core.factory.CheckDataFactory;
import com.ehome.poct.core.repository.check.GoldRequestLogRepository;
import com.ehome.poct.core.repository.check.GoldCheckRepository;
import org.springframework.beans.factory.annotation.Autowired;
import com.ehome.poct.core.api.dto.check.CheckParamDTO;
import com.ehome.poct.core.api.vo.check.*;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

/**
 * 金标仪检测服务实现
 *
 * @author cq
 * @since 2022/03/02 17:44
 **/
@Service
public class
GoldCheckServiceImpl implements CheckService, AbstractCheckService {

    @Autowired
    private GoldAlgoService algoService;
    @Autowired
    private GoldRequestLogRepository requestLogRepository;
    @Autowired
    private GoldCheckRepository goldCheckRepository;

    @Override
    public void handleDeviceInfo(String sno, Integer deviceType, TestDeviceDTO device) {
        if (null == device) {
            throw new BizException(DomainBizCode.NO_DEVICE);
        }
        if (1 != device.getStatus()) {
            throw new BizException(DomainBizCode.DEVICE_NOT_BAND_CLINIC);
        }
    }


    @Override
    public void handleClinicInfo(TestDeviceDTO device, Long clinicId, ClinicDTO clinic) {
        if (null == clinic) {
            throw new BizException(DomainBizCode.CLIENT_NOT_FOUND);
        }
        //校验诊所和设备是否匹配
        if (!device.getTermClinicId().equals(clinicId)) {
            throw new BizException(DomainBizCode.CLINIC_BIND_DEVICE_NOT_SAME);
        }
        // 特殊账号 需判断有效期
        CanContinueCheck(clinic);
    }


    private Boolean CanContinueCheck(ClinicDTO ClinicDto) {
        //如果账户为特殊账户且effective_start和effective_end为空或者不在时间段内（时间为datetime）则不能做检测，也不能检测分佣不能返佣不能提现
        //如果账户为特殊账户且effective_start和effective_end在时间段内 可以做检测，不能检测分佣，也不能返佣，可以提现
        if (1 == ClinicDto.getSpecialAccountType()) {
            if (null == ClinicDto.getEffectiveStart() || null == ClinicDto.getEffectiveEnd()) {
                throw new BizException(DomainBizCode.SPECIAL_CLIENT_NOT_EFFECTIVE);
            }
            if (LocalDateTime.now().isAfter(ClinicDto.getEffectiveStart()) && LocalDateTime.now().isBefore(ClinicDto.getEffectiveEnd())) {
                return true;
            }
            throw new BizException(DomainBizCode.SPECIAL_CLIENT_NOT_EFFECTIVE);
        }
        //默认都可以
        return true;
    }

    @Override
    public AlgoRequestLog algoProcess(CheckParamDTO paramDto, SampleMaterialDTO board) {
        //算法请求参数封装
        final var algoReqDTO = new GoldCheckAlgoReqDTO(paramDto.getDevice().getSno(), paramDto.getDevice().getVersion(), paramDto.getPath(), paramDto.getBucketName());
        //调用算法
        GoldCheckAlgoRspDTO rspDTO = algoService.getAlgoResultData(algoReqDTO);
        //根据 传入的批次 和检测类型 特殊处理下 检测类型
        handleStripType(rspDTO);
        if (rspDTO.getErrorCode() != 0) {
            // 保存异常数据
            Long testDataErrorDetailId = requestLogRepository.saveErrorDetailLog(paramDto.getDevice(), paramDto.getPath(), paramDto.getBucketName(), rspDTO);
            //检测数据 算法数据结果保存
            requestLogRepository.saveTestDataAlgoDetail(rspDTO.getOriginData(), testDataErrorDetailId);
            //算法请求日志记录
            requestLogRepository.saveAlgoReqLog(paramDto.getDevice().getSno(), paramDto.getDevice().getTermClinicId(), "", JSONUtil.toJsonStr(algoReqDTO), testDataErrorDetailId);
            throw new BizException(20030101, rspDTO.getMsg());
        }
        //保存正常数据
        Long testDataDetailId = requestLogRepository.saveDetailLog(paramDto.getDevice(), paramDto.getPath(), paramDto.getBucketName(), rspDTO);
        //检测数据 算法数据结果保存
        requestLogRepository.saveTestDataAlgoDetail(rspDTO.getOriginData(), testDataDetailId);
        return new AlgoRequestLog(null, null, JSONUtil.toJsonStr(rspDTO), paramDto.getDeviceSno(), paramDto.getPath());
    }


    /**
     * 根据 传入的批次 和检测类型 特殊处理下 检测类型
     * 目前只有苏中  的尿微量蛋白 1-2 批次 是要按照半定量半定性来处理
     *
     * @param rspDTO 算法返回数据
     * @return 处理之后算法返回数据
     */
    private GoldCheckAlgoRspDTO handleStripType(GoldCheckAlgoRspDTO rspDTO) {
        if (ValueConst.VAL_0.equals(rspDTO.getErrorCode())) {
            if (StripTypeConst.MALB.equals(rspDTO.getData().getTypeId())) {
                if (rspDTO.getData().getBatchNo() <= ValueConst.VAL_3) {
                    rspDTO.getData().setTypeId(StripTypeConst.MALB_H);
                }
            }
        }
        return rspDTO;
    }

    @Override
    public CheckProcessResultVO handleCheck(CheckParamDTO param, ClinicDTO clinic, TestDeviceDTO device) {
        //【检测流程】 检验设备信息
        handleDeviceInfo(param.getDeviceSno(), param.getDeviceType(), device);
        //【检测流程】 校验诊所信息
        handleClinicInfo(device, param.getClinicId(), clinic);
        // 上传图片 在controller层完成上传
        //【检测流程】 远程算法调用
        AlgoRequestLog algoLog = algoProcess(param, null);
        //【检测流程】 预处理算法处理的数据
        GoldCheckDataDTO checkData = (GoldCheckDataDTO) this.handleAlgoData(param, algoLog.getResponseContent(), device, clinic, null, algoLog);
        return CheckDataFactory.toGoldCheckResultVO(device, clinic, null, algoLog, checkData);
    }

    @Override
    public SampleMaterialDTO handleSamplematerial(CheckParamDTO paramDTO) {
        //todo
        return null;
    }

    @Override
    public CheckDataDTO handleAlgoData(CheckParamDTO param, String algoData, TestDeviceDTO device, ClinicDTO clinic,
                                       SampleMaterialDTO material, AlgoRequestLog algoLog) {
        //【业务异常检验】
        GoldCheckAlgoRspDTO algoRspDTO = JSONUtil.toBean(algoData, GoldCheckAlgoRspDTO.class);
        //检验诊所检验项权限
        var limit = goldCheckRepository.getStripLimitByClinicId(clinic.getTermClinicId());
        Optional.ofNullable(limit).ifPresent(l -> {
            if (l.getLimitType().equals(10) || CollUtil.contains(Arrays.asList(l.getStripTypeCodes().split(",")), algoRspDTO.getData().getTypeId())) {
                throw new BizException(DomainBizCode.FORBIDDEN_STRIP_TYPE_CHECK);
            }
        });
        //根据检测类型码获取 检测试纸相关配置
        TestConfPoctStripTypeDTO stripTypeDTO = goldCheckRepository.getPoctStripTypeByCode(algoRspDTO.getData().getTypeId());
        if (null == stripTypeDTO) {
            throw new BizException(DomainBizCode.STRIP_TYPE_NOT_EXIST);
        }
        //通过类型和批次获取检测类型批次信息
        TestConfPoctStripMappingDTO stripMappingDTO = goldCheckRepository.getPoctStripMappingByCodeAndBatch(algoRspDTO.getData().getTypeId(), algoRspDTO.getData().getBatchNo());
        if (null == stripMappingDTO) {
            throw new BizException(111131, "没有找到此(" + stripTypeDTO.getName() + ")对应的(" + algoRspDTO.getData().getBatchNo() + ")批次信息！");
        }
        if (stripMappingDTO.getEffectiveTime().isBefore(LocalDateTime.now())) {
            throw new BizException(DomainBizCode.TEST_STRIP_EXPIRED);
        }
        return new CellCheckDataDTO(algoLog.getId(), param.getClinicId(), param.getPatientId(), param.getType() == 1 ? 100 : 121,
                param.getDeviceSno(), param.getBoardSno(), 1, param.getPath(), null);
    }

    @Override
    public CheckStatusVO pollGetStatus(Long id) {
        return null;
    }

    @Override
    public CheckStatusVO manualGetStatus(Long id) {
        return null;
    }

    @Override
    public boolean updateResult(Long reqId, List<String> msg, String result, String morphology, String chart, String images, Boolean hasZero) {
        return false;
    }

    /**
     * 校验板子是否存在
     *
     * @param sno
     * @return
     */
    @Override
    public Boolean boardIsExist(String sno) {
        return true;
    }

    /**
     * 校验版本 返回板子其他信息
     *
     * @param sno
     * @return
     */
    @Override
    public CellBoardValidVO boardThickness(String sno) {
        return null;
    }

    @Override
    public CheckDataVO getCheckData(Long id) {
        return new GoldCheckDataVO();
    }

    @Override
    public CheckProcessResultVO saveLocalAlgodata(AlgoLocalDataDTO algoDto) {
        return null;
    }
}
